Docker Kata 6: Creating Docker Images

Learn to create an image from a modified container and with Dockerfile.

The previous katas have used images provided on Docker Hub. Most of those images are created and managed by software vendors.

This kata will demonstrate how we can define and build our own images for our own use or to distribute to others. This kata will cover two ways to create an image:

  • Commit changes to a modified container.
  • Build an image from a Dockerfile.

Step 1: Create an image from a modified container#

First, stop and remove all the containers and create an image from a modified container.

The output will be something like this:

Commands

Parameter/Command

Description

mkdir dockerimage

cd dockerimage

This creates, and then changes to, a new directory called dockerimage.

cp ../index.html .

This copies the index.html file from the parent directory to the dockerimage directory.

ls

This lists the files in the dockerimage directory. The index.html file should be listed.

These commands create a new directory called dockerimage and copy a sample index.html file into that directory.

The command to run a disconnected NGINX container is given below.

If we run the command above, the output will be something like this:

Running a disconnected NGINX container

Commands

Parameter

Description

docker container

This is the parent command.

run

This runs a container.

--name

This assigns a name to a container.

web

This is the name to assign to the container.

-d

This runs a container in disconnected mode.

-p

This publishes a port from the container to the host.

80:80

This publishes port 80 on the container to port 80 on the host.

nginx

This is the name of the image to run.

This command starts an NGNIX container using the same command from Kata 4.

The command to copy a file into the container is given below.

After execution of the command above, the result will be something like this:

Copying file into container

Commands

Parameter

Description

docker container

This is the parent command.

cp

The cp command copies a file to a container from the host, or vice versa.

index.html

This is the name of the file to copy into the container.


web:/usr/share/nginx/html/index.html

This is the image and the path. The name of the container to which the file should be copied is before the colon.

The path inside the container to which the file should be copied follows the colon. The effect is that the index.html file is copied into the container.

The cp command copies files between containers and their hosts. This step copied the index.html file from the host to the container.

The command to open the NGINX server page is given below.

The result will be something like this:

Opening the NGINX server page

The default NGINX welcome HTML we’ve seen previously has been replaced with the DevOps Katas custom page.

The curl command issues a request to the local system via HTTP. We can also use Firefox to view this page. Note that the welcome page has been modified. The index.html file copied in the previous step overwrote the default NGINX welcome page.

The command to list all the running containers is provided below.

The result of the command above will be something like this:

Listing all running containers

Commands

Parameter

Description

docker container

This is the parent command.

ls

This lists the running containers when combined with the docker container parent command.

This step lists all the running containers. The NGINX container we ran in an earlier step is running.

The command to create an image from the container is given below.

The output will be something like this:

Creating an image from the container

Commands

Parameter

Description

docker container

This is the parent command.

commit

The commit command stops a running container, and then creates a new image from that container. Changes to the file system of the container are persisted in the new image.

web

This is the name of the container from which to derive a new image.

kataimage_nginx

This is the name assigned to the new image.

The commit command is used to commit the changes to a container, thus creating a new image.

Recall in Kata 3 when we learned about file system changes in a container. When we copied the index.html file from the host to the NGINX container, we modified the container, but not the image from which that container was started. The commit command creates a new image called kataimage_nginx that includes that change.

The command to list all the images is given below.

When we run the command above, the result displayed will be something like:

Listing all images

Commands

Parameter

Description

docker image

This is the parent command.

ls

This lists images when combined with the docker image parent command. Note that the kataimage_nginx image is listed.

This command lists all the images. The kataimage_nginx image we created previously should be listed.

The command to run a disconnected container is given below.

After running the command above, the output will be something like this:

Running a disconnected container

Commands

Parameter

Description

docker container

This is the parent command.

run

This runs a new container.

-d

This runs a container in disconnected mode.

-p

This publishes a container port to a host port.

81:80

This publishes container port 80 to host port 81.

kataimage_nginx

This is the name of the image to run.

This command runs a second NGINX container, this time using the kataimage_nginx image we created in the previous step.

The command to view the page of the container is given below.

The output of the command above will be something like this:

Opening the NGINX server page

The curl command issues a request to the local system via HTTP. Note that the welcome page is the customized DevOps katas welcome page. The kataimage_nginx image includes the modified index.html file.

Step 2: Create an Image with a Dockerfile#

First, stop and remove all the containers.

The command to create a file is given below:

Enter (or copy/paste) the following text into the editor:

FROM nginx  
ADD index.html /usr/share/nginx/html/index.html  
RUN chmod 644 /usr/share/nginx/html/index.html 

The output will be something like:

Creating a docker file

Commands

Parameter/Command

Description

nano Dockerfile

The nano part is a text editor. This command creates a new file called Dockerfile.

FROM nginx

The first line in the Dockerfile is always FROM. This indicates the base image that will be used to create the image defined by a Dockerfile. This Dockerfile specifies the NGINX image as the base.

ADD index.html /usr/share/nginx/html/index.html

The ADD directive adds a file to the image when it's built. This can be a local file or a URL. ADD is followed by the path to the source file, then the path to which the file should be copied in the new image.


RUN chmod 644 /usr/share/nginx/html/index.html

The RUN directive runs a command within the container. This command uses the chmod Linux command to change the permissions of the index.html file copied into the image. This permission change allows the NGINX server to read the index.html file.

This step demonstrates the second method to create Docker images: a Dockerfile. The result is the same as the previous step; however, the commit method is an imperative method for creating images. That’s good for experimentation and testing, but a declarative method is better for building containers as part of a software delivery process.

A Dockerfile uses a declarative syntax to describe the contents of a container:

-The FROM part indicates the base image from which to create a new image. Any existing image may be used as the basis for any new image (except scratch, which is a non-runnable image used as a “bare-bones” base image). This step uses the NGINX image as its base image. The build process starts a temporary container from the base image defined in the FROM directive, then executes the following directives, creating the image.

The ADD command adds a file to the image. The source can be a file on the local file system or a URL to a file on the web. This step adds the custom index.html file (the same file as the one in the previous step) to the image.

The RUN entries execute commands within the image as it’s built. This command updates the permissions on the index.html file, which allows the NGINX HTTP server to read the file.

This Dockerfile builds a new image from the NGINX image. That image is available on Docker Hub. Let’s look at the Dockerfile for the official NGINX image to learn more about how Dockerfiles work.

Here’s the Dockerfile for the official NGINX image (current at the time of this writing):

FROM debian:jessie

MAINTAINER NGINX Docker Maintainers "docker-maint@nginx.com"

ENV NGINX_VERSION 1.11.10-1~jessie

RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys > 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 \
    && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> > /etc/apt/sources.list \
    && apt-get update \
    && apt-get install --no-install-recommends --no-install-suggests -\
                        ca-certificates \
                        nginx=${NGINX_VERSION} \
                        nginx-module-xslt \
                        nginx-module-geoip \
                        nginx-module-image-filter \
                        nginx-module-perl \
                        nginx-module-njs \
                        gettext-base \
    && rm -rf /var/lib/apt/lists/*

# forward request and error logs to Docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log

EXPOSE 80 443

CMD ["nginx", "-g", "daemon off;"]  

This Dockerfile includes some of the same directives that are in the Dockerfile for kataimage_nginx and some that aren’t.

The FROM directive indicates the base image of the official NGINX image. The official NGINX image is based on the Jessie version of the official Debian Linux container. Public and official images are typically layered in this fashion. Base images start at the bottom or first layer with official OS distributions. Additional layers add software to the base image, creating a specialized container made for a specific purpose, such as a web server.

The MAINTAINER directive is deprecated in the current version of Docker. It has been replaced by the AUTHOR directive, which includes contact information for the creator of the Dockerfile.

The ENV directive sets the environment variables in the target image.

The following RUN command combines multiple installations and file system changes in a single command. The double ampersand (&&) may be used in Linux to execute multiple commands in one line. This technique is important when defining an image.

Docker uses a specialized layered file system to define images. When an image is created using FROM, a new layer is added to the file system that defines the image. The new top layer represents all the differences (installed programs, added files) between the base image and the new image. This layering system keeps images small by storing only the differences between the layers. Keeping images as small as possible makes image deployment faster and reduces storage space requirements for images and containers.

Each RUN command creates a new file system layer. If each of the commands in the NGINX Dockerfile were run separately, a new layer would be created for each execution. This would create many new layers, resulting in a larger image. Running all the commands in a single execution creates just one new layer.

The EXPOSE directive indicates to Docker that the container will listen on the port numbers specified. This isn’t the same as publishing the ports. The -p parameter is still necessary when running a container. It’s possible to use the -P (capital “P”) parameter to publish all the ports identified with EXPOSE. The -P parameter will publish all the exposed ports to the same port on the host. Given this NGINX Dockerfile, these two commands have the same effect:

docker container run -d -p 80:80 -p 443:443 nginx
docker container run -d -P nginx

The last directive in the NGINX Dockerfile is CMD:

CMD ["nginx", "-g", "daemon off;"]

There can only be one CMD directive in a Dockerfile (if there is more than one, the last one defined is the only one that will run).

The CMD directive is one of the methods to define the start command of the container. This method defines the program to run and its parameters:

CMD ["nginx", "-g", "daemon off;"]

Commands

Parameter/Command

Description

nginx

This is the NGINX HTTP server program.

-g

This indicates that the following parameters are global configuration directives. This changes the configuration for this execution of the NGINX server.


daemon off

This configures the NGINX server process to run in the foreground as the primary process, as opposed to running in the background as a service. This is recommended for running NGINX in a container.

The command to build the image using Dockerfile is given below.

The result of the command above will be something like this:

Building the image using a Dockerfile

Commands

Parameter

Description

docker image

This is the parent command.

build

This builds a new image from a Dockerfile when combined with the Docker image parent command.

-t

This assigns a name, and if desired, a tag to the new image.

katadockerfile_image .

This is the name of the new image. The period after the name indicates the path to the Dockerfile. In Linux, a single period indicates the current directory.

The build subcommand creates a new Docker image from a Dockerfile.

The command to list all the images is given below.

The result will be something like this:

Listing all images

Commands

Parameter

Description

docker image

This is the parent command.

ls

This lists the images when combined with the docker image parent command.

This command lists all the images. The katadockerfile_image image should be listed.

The command to run a disconnected container is given below.

When we execute the command above, the output will be something like this:

Running a disconnected container

Commands

Parameter

Description

docker container

This is the parent command.

run

This runs a container.

-d

This runs a container in disconnected mode.

-p

This publishes a container port to a host port.

80:80

This publishes container port 80 to host port 80.

katadockerfile_image

This is the name of the image to run.

This command runs the image that was created in the previous step using docker image build.

The command to view the page in the container is given below.

The output will be something like this:

Viewing the server page in a container

This command returns the response from the NGINX container using curl. As expected, the result is the same as the previous kata step. This method, however, uses a declarative method. The Dockerfile used to create this image can be added to source control and used as part of an automated build process.

Practice commands#

We’ve given a terminal and table containing a list of commands discussed in this lesson. Try out these commands after running the terminal, and check out the results!

Commands

Step

Command

This creates a dockerimage directory.

mkdir dockerimage

This changes to the dockerimage directory.

cd dockerimage

This copies the index.html file in the parent to the `dockerimage` directory.

cp ../index.html .

This lists the files in `dockerimage`.

ls

Run a disconnected NGINX container named web and maps port 80 between the host and container.


docker container run --name web -d -p 80:80 nginx

This copies the index.html file into the web container.

docker container cp index.html web:/usr/share/nginx/html/index.html

This opens the NGINX server page using curl.

curl localhost

This lists all the running containers.

docker container ls

This creates an image from the web container named kataimage_nginx.

docker container commit web kataimage_nginx

This lists all the images.

docker image ls

This runs a disconnected container from kataimage_nginx and maps host port 81 to container port 80.


docker container run -d -p 81:80 kataimage_nginx

This views the page of the kataimage_nginx container using curl.


curl localhost:81

This stops and removes all the containers.

docker container stop $(docker container ls -q)

docker container rm $(docker container ls -aq)

This creates a file called Dockerfile with the nano text editor.

nano Dockerfile

This enters the Dockerfile directives into the text editor.

FROM nginx

ADD index.html /usr/share/nginx/html/index.html

RUN chmod 644 /usr/share/nginx/html/index.html

This builds the image using the Dockerfile and creates an image called katadockerfile_image.

docker image build -t katadockerfile_image .

This lists all the images.

docker image ls

This runs a disconnected container from katadockerfile_image maps host port 80 to container port 80.


docker container run -d -p 80:80 katadockerfile_image

This views the page in the katadockerfile_image container using curl.


curl localhost

Terminal 1
Terminal

Click to Connect...

Docker Kata 5: Docker Networking

Quiz Yourself on Docker Commands